package com.hm.base.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hm.base.auto.su.BeanUtil;
import com.hm.base.auto.su.R.RedisKey;
import com.hm.base.domain.Menu;
import com.hm.base.domain.Organization;
import com.hm.base.domain.OrganizationRole;
import com.hm.base.domain.RoleMenu;
import com.hm.base.domain.Subscriber;
import com.hm.base.domain.SubscriberOrganization;
import com.hm.base.domain.SubscriberRole;
import com.hm.base.mapper.MenuMapper;
import com.hm.base.mapper.OrganizationMapper;
import com.hm.base.mapper.OrganizationRoleMapper;
import com.hm.base.mapper.RoleMapper;
import com.hm.base.mapper.RoleMenuMapper;
import com.hm.base.mapper.SubscriberMapper;
import com.hm.base.mapper.SubscriberOrganizationMapper;
import com.hm.base.mapper.SubscriberRoleMapper;
import com.hm.base.vo.LoginSubscriberVo;
import com.hm.base.vo.MenuVo;
import com.hm.base.vo.OrganizationVo;
import com.hm.base.vo.RoleMenuVo;
import com.hm.base.vo.RoleVo;
import com.hm.common.def.DataStatusDef;
import com.hm.common.exception.ErrorCode;
import com.hm.common.exception.ServiceException;
import com.hm.common.redis.jedis.JedisFactory;
import com.hm.common.redis.jedis.su.JedisHandler;
import com.hm.common.redis.jedis.su.JedisHandlerSupport;
import com.hm.common.util.CommonUtil;
import com.hm.common.util.DateUtil;
import com.hm.common.util.EncryptUtil.AES;
import com.hm.common.util.EncryptUtil.Md5;

/**
 * @author shishun.wang
 * @date 下午4:58:25 2017年6月2日
 * @version 1.0
 * @describe
 */
@Service
public class AuthorizationServiceImpl implements AuthorizationService {

	@Autowired
	private SubscriberMapper subscriberMapper;

	@Autowired
	private RoleMapper roleMapper;

	@Autowired
	private MenuMapper menuMapper;

	@Autowired
	private OrganizationMapper organizationMapper;

	@Autowired
	private JedisHandlerSupport jedisHandler;

	@Autowired
	private SubscriberOrganizationMapper subscriberOrganizationMapper;

	@Autowired
	private OrganizationRoleMapper organizationRoleMapper;

	@Autowired
	private SubscriberRoleMapper subscriberRoleMapper;

	@Autowired
	private RoleMenuMapper roleMenuMapper;

	@Override
	public LoginSubscriberVo login(String username, String password) {
		if (CommonUtil.isAnyEmpty(username, password)) {
			throw ServiceException.warning(ErrorCode.PARAMETERS_MISSING, "登陆用户名密码");
		}

		Subscriber subscriber = new Subscriber();
		subscriber.setAccount(username);
		subscriber.setUserPwd(Md5.getMD5Code(password));

		subscriber = subscriberMapper.login(subscriber);
		if (CommonUtil.isEmpty(subscriber)) {
			throw ServiceException.warn("用户名/密码错误");
		}

		final LoginSubscriberVo subscriberVo = new LoginSubscriberVo();
		BeanUtil.copyProperties(subscriber, subscriberVo);
		subscriberVo.setLastLoginTime(DateUtil.data2long(subscriber.getLastLoginTime()));

		long now = System.currentTimeMillis();
		subscriberVo.setToken(AES.encrypt(subscriber.getId() + ":" + now));
		subscriberVo.setCurrentLoginTime(now);

		final Long userId = subscriber.getId();

		jedisHandler.executeCommand(new JedisHandler() {

			@Override
			public Object handler(JedisFactory jedis) {
				jedis.set(RedisKey.SUBSCRIBER_LOGIN_GROUP + userId, JSON.toJSONString(subscriberVo));
				return null;
			}
		});
		return subscriberVo;
	}

	@Override
	public void logout(Long subscriberId, String username) {

	}

	@Override
	public List<RoleVo> loadUserRoles(Long subscriberId) {
		if (CommonUtil.isEmpty(subscriberId)) {
			throw ServiceException.warning(ErrorCode.REQUIRED_PARAMETERS_MISSING);
		}

		List<RoleVo> vos = new ArrayList<RoleVo>();
		roleMapper.loadUserRoles(subscriberId).forEach(role -> {
			RoleVo vo = new RoleVo();
			BeanUtil.copyProperties(role, vo);

			vos.add(vo);
		});

		return vos;
	}

	@Override
	public List<MenuVo> loadUserMenus(Long subscriberId) {
		if (CommonUtil.isEmpty(subscriberId)) {
			throw ServiceException.warning(ErrorCode.REQUIRED_PARAMETERS_MISSING);
		}

		return loopUserMenus(subscriberId, 0l);
	}

	private List<MenuVo> loopUserMenus(Long subscriberId, Long parentId) {
		Map<String, Object> param = new HashMap<String, Object>();
		param.put("subscriberId", subscriberId);
		param.put("parentId", parentId);

		List<MenuVo> vos = new ArrayList<MenuVo>();
		List<Menu> menus = menuMapper.loadUserMenus(param);
		if (CommonUtil.isEmpty(menus)) {
			return vos;
		}

		menus.forEach(menu -> {
			MenuVo vo = new MenuVo();
			BeanUtil.copyProperties(menu, vo);
			vo.setChilds(loopUserMenus(subscriberId, menu.getId()));

			vos.add(vo);
		});

		return vos;
	}

	@Override
	public LoginSubscriberVo loadLoginToken(Long subscriberId) {
		if (CommonUtil.isEmpty(subscriberId)) {
			throw ServiceException.warning(ErrorCode.REQUIRED_PARAMETERS_MISSING);
		}

		Object cacheObj = jedisHandler.executeCommand(new JedisHandler() {

			@Override
			public Object handler(JedisFactory jedis) {
				return jedis.get(RedisKey.SUBSCRIBER_LOGIN_GROUP + subscriberId);
			}
		});

		if (CommonUtil.isEmpty(cacheObj)) {
			return null;
		}

		return JSONObject.parseObject(cacheObj.toString(), LoginSubscriberVo.class);
	}

	@Override
	public List<OrganizationVo> loadUserOrganizations(Long subscriberId) {
		if (CommonUtil.isEmpty(subscriberId)) {
			throw ServiceException.warning(ErrorCode.REQUIRED_PARAMETERS_MISSING);
		}

		return loopUserOrganizations(subscriberId, 0l);
	}

	private List<OrganizationVo> loopUserOrganizations(Long subscriberId, Long parentId) {
		Map<String, Object> param = new HashMap<String, Object>();
		param.put("subscriberId", subscriberId);
		param.put("parentId", parentId);

		List<OrganizationVo> vos = new ArrayList<OrganizationVo>();
		List<Organization> organizations = organizationMapper.loadUserOrganizations(param);
		if (CommonUtil.isEmpty(organizations)) {
			return vos;
		}
		organizations.forEach(organization -> {
			OrganizationVo vo = new OrganizationVo();
			BeanUtil.copyProperties(organization, vo);
			vo.setChilds(loopUserOrganizations(subscriberId, organization.getId()));

			vos.add(vo);
		});

		return vos;
	}

	@Override
	public List<RoleVo> loadUserOrganizationRoles(Long subscriberId) {
		if (CommonUtil.isEmpty(subscriberId)) {
			throw ServiceException.warning(ErrorCode.REQUIRED_PARAMETERS_MISSING);
		}

		List<RoleVo> vos = new ArrayList<RoleVo>();
		roleMapper.loadUserOrganizationRoles(subscriberId).forEach(role -> {
			RoleVo vo = new RoleVo();
			BeanUtil.copyProperties(role, vo);
			vos.add(vo);
		});
		return vos;
	}

	@Override
	public List<MenuVo> loadUserOrganizationMenus(Long subscriberId) {
		if (CommonUtil.isEmpty(subscriberId)) {
			throw ServiceException.warning(ErrorCode.REQUIRED_PARAMETERS_MISSING);
		}

		return loopUserOrganizationMenus(subscriberId, 0l);
	}

	private List<MenuVo> loopUserOrganizationMenus(Long subscriberId, Long parentId) {
		Map<String, Object> param = new HashMap<String, Object>();
		param.put("subscriberId", subscriberId);
		param.put("parentId", parentId);

		List<MenuVo> vos = new ArrayList<MenuVo>();
		List<Menu> menus = menuMapper.loadUserOrganizationMenus(param);
		if (CommonUtil.isEmpty(menus)) {
			return vos;
		}

		menus.forEach(menu -> {
			MenuVo vo = new MenuVo();
			BeanUtil.copyProperties(menu, vo);
			vo.setChilds(loopUserMenus(subscriberId, menu.getId()));

			vos.add(vo);
		});

		return vos;
	}

	@Override
	public void settingUserOrganizations(Long subscriberId, List<Long> organizations) {
		if (CommonUtil.isEmpty(subscriberId)) {
			throw ServiceException.warning(ErrorCode.REQUIRED_PARAMETERS_MISSING);
		}
		SubscriberOrganization organization = new SubscriberOrganization();
		organization.setUserId(subscriberId);
		subscriberOrganizationMapper.delete(organization);

		if (CommonUtil.isEmpty(organizations)) {
			return;
		}

		List<SubscriberOrganization> contents = new ArrayList<SubscriberOrganization>();
		organizations.stream().parallel().forEach(organizationId -> {
			SubscriberOrganization model = new SubscriberOrganization();
			{
				model.setOrganizationId(organizationId);
				model.setUserId(subscriberId);
			}
			contents.add(model);
		});

		subscriberOrganizationMapper.insertList(contents);
	}

	@Override
	public void settingUserOrganizationRoles(Long organizationId, List<Long> roles) {
		if (CommonUtil.isEmpty(organizationId)) {
			throw ServiceException.warning(ErrorCode.REQUIRED_PARAMETERS_MISSING);
		}
		OrganizationRole organizationRole = new OrganizationRole();
		organizationRole.setOrganizationId(organizationId);
		organizationRoleMapper.delete(organizationRole);

		if (CommonUtil.isEmpty(roles)) {
			return;
		}

		List<OrganizationRole> contents = new ArrayList<OrganizationRole>();
		roles.stream().parallel().forEach(roleId -> {
			OrganizationRole model = new OrganizationRole();
			{
				model.setOrganizationId(organizationId);
				model.setRoleId(roleId);
			}
			contents.add(model);
		});

		organizationRoleMapper.insertList(contents);
	}

	@Override
	public void settingUserRoles(Long subscriberId, List<Long> roles) {
		if (CommonUtil.isEmpty(subscriberId)) {
			throw ServiceException.warning(ErrorCode.REQUIRED_PARAMETERS_MISSING);
		}

		SubscriberRole subscriberRole = new SubscriberRole();
		subscriberRole.setSubscriberId(subscriberId);
		subscriberRoleMapper.delete(subscriberRole);

		if (CommonUtil.isEmpty(roles)) {
			return;
		}

		List<SubscriberRole> contents = new ArrayList<SubscriberRole>();
		roles.stream().parallel().forEach(roleId -> {
			SubscriberRole model = new SubscriberRole();
			{
				model.setSubscriberId(subscriberId);
				model.setRoleId(roleId);
			}
			contents.add(model);
		});

		subscriberRoleMapper.insertList(contents);
	}

	@Override
	public void settingRoleMenus(Long roleId, List<Long> menus) {
		if (CommonUtil.isEmpty(roleId)) {
			throw ServiceException.warning(ErrorCode.REQUIRED_PARAMETERS_MISSING);
		}

		RoleMenu roleMenu = new RoleMenu();
		roleMenu.setRoleId(roleId);
		roleMenuMapper.delete(roleMenu);

		if (CommonUtil.isEmpty(menus)) {
			return;
		}

		List<RoleMenu> contents = new ArrayList<RoleMenu>();
		menus.stream().parallel().forEach(menuId -> {
			RoleMenu model = new RoleMenu();
			{
				model.setMenuId(menuId);
				model.setRoleId(roleId);
			}
			contents.add(model);
		});

		roleMenuMapper.insertList(contents);
	}

	@Override
	public List<RoleMenuVo> loadRoleMenus(Long roleId) {
		if (CommonUtil.isEmpty(roleId)) {
			throw ServiceException.warning(ErrorCode.REQUIRED_PARAMETERS_MISSING);
		}

		List<RoleMenuVo> vos = new ArrayList<RoleMenuVo>();
		loadRoleMenus(roleId, 0l, vos);

		return vos;
	}

	private void loadRoleMenus(Long roleId, Long menuParentId, List<RoleMenuVo> vos) {
		Menu menu = new Menu();
		menu.setParentId(menuParentId);
		menu.setStatus(DataStatusDef.ENABLE.name());

		menuMapper.select(menu).forEach(item -> {
			RoleMenu roleMenu = new RoleMenu();
			{
				roleMenu.setRoleId(roleId);
				roleMenu.setMenuId(item.getId());
			}

			RoleMenuVo vo = new RoleMenuVo();
			vo.setId(item.getId());
			vo.setPId(menuParentId);
			vo.setName(item.getName());
			vo.setOpen(false);
			vo.setChecked(CommonUtil.isNotEmpty(roleMenuMapper.select(roleMenu)));

			vos.add(vo);

			this.loadRoleMenus(roleId, item.getId(), vos);
		});

	}

}
